package org.airlink.persistence.query {
	import flash.data.SQLConnection;
	import flash.data.SQLResult;
	import flash.data.SQLStatement;
	import flash.errors.IllegalOperationError;
	import flash.utils.Dictionary;
	import flash.utils.describeType;
	
	import flex.persistence.EntityManager;
	import flex.persistence.EntityTransaction;
	import flex.persistence.FlushModeType;
	import flex.persistence.Query;
	import flex.persistence.exceptions.IllegalArgumentException;
	import flex.persistence.exceptions.NoResultException;
	import flex.persistence.exceptions.NonUniqueResultException;
	import flex.persistence.exceptions.PersistenceException;
	
	import mx.core.ClassFactory;
	import mx.utils.ObjectUtil;
	import mx.utils.StringUtil;
	
	import org.airlink.persistence.Entity;
	import org.airlink.persistence.EntityIntrospector;
	import org.airlink.persistence.EntityManagerImpl;
	import org.airlink.persistence.associations.Association;
	import org.airlink.persistence.associations.BasicField;
	import org.airlink.persistence.associations.ManyToManyAssociation;
	import org.airlink.persistence.associations.ManyToOneAssociation;
	import org.airlink.persistence.associations.OneToManyAssociation;
	import org.airlink.persistence.associations.OneToOneAssociation;
	
	public class NativeQuery extends AbstractQuery {
		
		public function NativeQuery(sql:String, resultClass:Class, entityManager:EntityManagerImpl, transaction:EntityTransaction=null) {
			super(sql, entityManager, transaction);
			this.resultClass = resultClass;
			if(resultClass) {
				isSimple = ObjectUtil.isSimple(new resultClass());
				if(!isSimple) entityManager.introspector.loadMetadata(resultClass);
			}
		}
		
		override public function executeUpdate():int {
			throw new IllegalOperationError("Not implemented.");
		}
		
		override public function getResultList():Array {
			transaction.begin();
			var statement:SQLStatement = new SQLStatement();
			statement.sqlConnection = transaction.dbConnection as SQLConnection;
			statement.text = query;
			this.computeParameters(statement);
			statement.execute();
			var sqlResult:SQLResult = statement.getResult();
			var resultsSql:Array = sqlResult.data;
			var results:Array = new Array();
			for each(var result:Object in resultsSql) {
				results.push(transformResult(result));
			}
			transaction.commit();
			return results;
		}
		
		override public function getSingleResult():Object {
			try {
				
				transaction.begin();
				var statement:SQLStatement = new SQLStatement();
				statement.sqlConnection = transaction.dbConnection as SQLConnection;
				statement.text = query;	
				this.computeParameters(statement);
				statement.execute();
				var sqlResult:SQLResult = statement.getResult();			
				var resultsSql:Array = sqlResult.data;
				var results:Array = new Array();
				if(resultsSql) {
					if(resultsSql.length>1) throw new NonUniqueResultException();
					var resultSql:Object = resultsSql[0];						
					return transformResult(resultSql)
				}
				
			} finally {
				transaction.commit();
			}
			throw new NoResultException();
		}
		
		protected function computeParameters(statement:SQLStatement):void {
			for(var key:String in this.parameters) {
				var val:Object = this.parameters[key];
				if(val is Date) val = val.time;
				statement.parameters[key] = val;
			}
		}
		
	}
}